import hashlib
import os
import re
import shutil
import uuid
from datetime import datetime, timedelta

from django.contrib.auth import logout
from django.db import transaction
from django.http import FileResponse
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from rest_framework.decorators import permission_classes
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from rest_framework_simplejwt.views import TokenObtainPairView

from apps.accounts.filters import UserFilter
from apps.accounts.handlers import init_menu
from apps.accounts.models import User, SystemSettings, UserPasswordHistory
from apps.accounts.serializers import UserSerializer, APITokenObtainPairSerializer, SystemSettingsSerializer, \
    UserInfoSerializer, APIUserLoginTokenObtainPairSerializer
from bases.messages import MSG_50001_ERROR_USER
from bases.response import SuccessResponse, FailResponse
from bases.viewsets import APIModelViewSet, APIUpdateOnlyViewSet, APIReadOnlyViewSet
from constants import LOG_PATH
from utils.system_settings.constant import INITIAL_PASSWORD, PASSWORD_VALID_DAYS, PASSWORD_REGEX, \
    DISABLE_PASSWORD_DUPLICATION_TIMES
from utils.system_settings.handler import get_system_setting
from utils.utils import create_folder


class APITokenObtainPairView(TokenObtainPairView):
    """
    用户登录请求API
    """
    serializer_class = APITokenObtainPairSerializer


class APIUserLoginTokenObtainPairView(TokenObtainPairView):
    """
    用户登录请求API
    """
    serializer_class = APIUserLoginTokenObtainPairSerializer


class UserLogoutView(APIView):
    """
    用户登出接口
    """
    def post(self, request):
        logout(request)
        return SuccessResponse()


class UserViewSet(APIModelViewSet):
    """
    用户增删改查通用API
    """
    queryset = User.objects.all().order_by('-is_active', 'id')
    serializer_class = UserSerializer
    filter_class = UserFilter


class UserInfoViewSet(APIReadOnlyViewSet):
    """
    用户增删改查通用API
    """
    queryset = User.objects.all().order_by('-is_active', 'id')
    serializer_class = UserInfoSerializer


class SystemSettingsViewSet(APIUpdateOnlyViewSet):
    """
    系统参数改查通用接口
    """
    queryset = SystemSettings.objects.filter(is_active=True).order_by('id')
    serializer_class = SystemSettingsSerializer


class ResetPassword(APIView):
    """
    密码重置API
    方法：POST
    参数：user (用户ID)
    """

    @transaction.atomic
    def post(self, request):
        user_id = request.data['user']

        initial_password = get_system_setting(INITIAL_PASSWORD)
        days = get_system_setting(PASSWORD_VALID_DAYS)
        curr_date = datetime.now().date()

        user = User.objects.get(id=user_id)
        user.set_password(initial_password)
        user.valid_date = curr_date
        user.invalid_date = curr_date + timedelta(days=int(days))
        user.init_status = True
        user.save()
        return SuccessResponse()


class UserMenuPermission(APIView):

    def get(self, request):
        menu_list = init_menu(request)
        return SuccessResponse(menu_list)


@permission_classes((AllowAny,))
class UpdatePassword(APIView):
    """
    密码修改API
    方法：POST
    参数：user_id, old_password、new_password
    """

    @transaction.atomic
    def post(self, request):
        user_name = request.data['user_name']
        old_password = request.data['old_password']
        new_password = request.data['new_password']

        md5 = hashlib.md5()
        md5.update(new_password.encode("utf8"))
        md5_password = md5.hexdigest()

        password_regex = get_system_setting(PASSWORD_REGEX)
        if password_regex:
            if not re.match(password_regex, new_password):
                # Translators: 密码强度不足，必须包含小写英文字符、大写英文字符、数字(同一字符或者数字不可连续)且长度必须是8-16位
                error_msg = _('password complexity requirements')
                return FailResponse(str(error_msg))

        times = get_system_setting(DISABLE_PASSWORD_DUPLICATION_TIMES)
        if times:
            user_password_history = UserPasswordHistory.objects.filter(user__username=user_name).order_by(
                '-created_date')[:int(times)]

            for history in user_password_history:
                if history.md5_password == md5_password:
                    # Translators: 密码已经在最近n次中被使用过，请更换其他密码
                    error_msg = _('password used %(num)s times') % {'num': times}
                    return FailResponse(str(error_msg))

        if re.match('^.+@.+$', user_name):  # 邮箱登录正则
            try:
                user = User.objects.get(email__exact=user_name)
            except User.DoesNotExist:
                return FailResponse(str(MSG_50001_ERROR_USER))
        else:  # 用户名登录
            try:
                user = User.objects.get(username__exact=user_name)
            except User.DoesNotExist:
                return FailResponse(str(MSG_50001_ERROR_USER))

        if user.check_password(old_password):
            days = get_system_setting(PASSWORD_VALID_DAYS)
            user.set_password(new_password)
            curr_date = datetime.now().date()
            user.init_status = False
            user.valid_date = curr_date
            user.invalid_date = curr_date + timedelta(days=int(days))
            user.save()
            UserPasswordHistory.objects.create(user=user, md5_password=md5_password)
            return SuccessResponse()
        else:
            # Translators: 原始密码错误
            error_msg = _('the original password is wrong')
            return FailResponse(str(error_msg))


class UpdateAvatar(APIView):
    """
    头像更新 API
    方法：POST
    参数：avatar （图片）
    """

    @transaction.atomic
    def post(self, request):
        user = request.user

        avatar = request.FILES.get('avatar')

        file_name = "A" + str(uuid.uuid4()) + '.PNG'

        upload_path = "media/avatar"

        create_folder(upload_path)

        file_path = os.path.join(upload_path, file_name)

        with open(file_path, 'wb') as f:
            for i in avatar.chunks():
                f.write(i)

        avatar_str = "avatar/" + file_name
        user.avatar = avatar_str
        user.save()
        return SuccessResponse({"avatar": file_path})


class LogsDirectoryStructure(APIView):

    def get(self, request):

        # # 获取目录下的所有条目（文件和子目录）
        entries = os.listdir(LOG_PATH)
        entries.sort(reverse=True)

        request_log = []
        debug_log = []

        for entry in entries:
            if os.path.isdir(os.path.join(LOG_PATH, entry)):
                if 'debug' in str(entry):
                    debug_dict = dict()
                    debug_dict['id'] = entry
                    debug_dict['label'] = entry
                    debug_log.append(debug_dict)
                else:
                    request_dict = dict()
                    request_dict['id'] = entry
                    request_dict['label'] = entry
                    request_log.append(request_dict)

        data = []
        data.append({'id': 'request_log', 'label': 'Request Logs', 'children': request_log})
        data.append({'id': 'debug_log', 'label': 'Debug Logs', 'children': debug_log})

        return SuccessResponse(data)


class LogFileHandle(APIView):

    def get(self, request):
        folder_name = request.GET.get('folder')
        directory = os.path.join(LOG_PATH, folder_name)
        # 获取目录下的所有文件和目录名
        entries = os.listdir(directory)
        entries.sort(reverse=True)

        # 遍历每个条目
        file_list = []
        for entry in entries:
            full_path = os.path.join(directory, entry)  # 获取完整路径
            if os.path.isfile(full_path):  # 判断是否是文件
                file_dict = dict()
                file_size = os.path.getsize(full_path)  # 获取文件大小，单位是字节
                modification_time = os.path.getmtime(full_path)  # 获取文件最后修改时间
                file_dict['folder_name'] = folder_name
                file_dict['file_name'] = entry
                file_dict['file_size'] = f'{round(file_size / 1024)} KB'
                file_dict['modification_time'] = datetime.fromtimestamp(modification_time).strftime('%Y-%m-%d %H:%M:%S')
                file_list.append(file_dict)
        return SuccessResponse(file_list)


@permission_classes((AllowAny,))
class LogFileStream(APIView):

    def get(self, request, folder, filename):
        log_file = os.path.join(LOG_PATH, folder, filename)

        response = FileResponse(open(log_file, 'rb'), filename=filename)
        return response


class DownloadLogFile(APIView):

    def get(self, request):
        folder_name = request.GET.get('folder')
        filename = request.GET.get('filename')

        file_url = reverse('log_file_stream', kwargs={'folder': folder_name, 'filename': filename})
        return SuccessResponse({'log_file': file_url})


class DeleteLogFile(APIView):

    def post(self, request):
        folder_name = request.data.get('folder')
        filename = request.data.get('filename')
        log_file = os.path.join(LOG_PATH, folder_name, filename)

        # 检查文件是否存在
        if os.path.exists(log_file):
            # 删除文件
            try:
                os.remove(log_file)
            except Exception as e:
                raise ValidationError(str(e))
        return SuccessResponse()


class DeleteLogFolder(APIView):

    def post(self, request):
        folder_name = request.data.get('folder')
        folder_path = os.path.join(LOG_PATH, folder_name)

        if os.path.exists(folder_path) and os.path.isdir(folder_path):
            try:
                shutil.rmtree(folder_path)
            except Exception as e:
                raise ValidationError(str(e))
        return SuccessResponse()
